package chapter3;

/**
 * 第三者机器人的主类
 * 
 * 我们将用手创建一个迷宫，并将其输入遗传算法的“评估种群”方法，
 * 然后该方法负责给一个带有传感器的抽象机器人打分。
 *
 * 个人认为，说明这个算法没有问题，但作者最后的结论说适应任意迷宫还是有问题的
 * 在这个迷宫中不会撞墙并不代表下一个迷宫不会撞墙
 * 书中的第5个位置（前和向前传感器打开）表现为左转，
 * 实际程序运行后有10右转 11左转（注意程序的左转和右转和3.3.2的例子是反的） 01前进
 * 从结果看01向前明显会撞墙
 *
 */
public class RobotController {

	/**
	 * 要运行的世代数的上限。大约50%的时间里，200代就足以找到这条路，
	 * 但是出于演示的目的，我们默认设置了这个值。
	 */
	public static int maxGenerations = 1000;

	public static void main(String[] args) {

		/**
		 * 我们会手写这个初始化迷宫，因为这个不是“迷宫生成算法”
		 * 
		 * 3s代表穿过迷宫的正确路线。1是无法通过的墙，0是有效的位置，
		 * 但不是正确的路线。你可以通过视觉跟随3s找到穿过迷宫的正确路径。
		 * 
		 * 如果您已经阅读了geneticalGorithm::istemittionOnConditionMet的文档块，
		 * 我提到我们不知道一个完美的解决方案是什么样的，所以我们能给算法的唯一约束是世代数。
		 * 这是真的也是假的。在这种情况下，因为我们是手工制作迷宫的，所以我们实际上知道获胜的体能:它是29，
		 * 或者说下面的3的个数！然而，我们不能把它作为终止条件；如果这个迷宫是按程序产生的，我们就不一定知道幻数是29。
		 * 
		 * As a reminder: 
		 * 0 = 空
		 * 1 = 墙
		 * 2 = 起始位置
		 * 3 = 路径
		 * 4 = 目标终点
		 */

		Maze maze = new Maze(new int[][] { 
			{ 0, 0, 0, 0, 1, 0, 1, 3, 2 }, 
			{ 1, 0, 1, 1, 1, 0, 1, 3, 1 },
			{ 1, 0, 0, 1, 3, 3, 3, 3, 1 }, 
			{ 3, 3, 3, 1, 3, 1, 1, 0, 1 }, 
			{ 3, 1, 3, 3, 3, 1, 1, 0, 0 },
			{ 3, 3, 1, 1, 1, 1, 0, 1, 1 }, 
			{ 1, 3, 0, 1, 3, 3, 3, 3, 3 }, 
			{ 0, 3, 1, 1, 3, 1, 0, 1, 3 },
			{ 1, 3, 3, 3, 3, 1, 1, 1, 4 } 
		});

		// Create genetic algorithm
		GeneticAlgorithm ga = new GeneticAlgorithm(200, 0.05, 0.9, 2, 10);
		Population population = ga.initPopulation(128);
		ga.evalPopulation(population, maze);
		// Keep track of current generation
		int generation = 1;
		// Start evolution loop
		//while (ga.isTerminationConditionMet(generation, maxGenerations) == false) {
		while (ga.isTerminationConditionMet2(generation, maxGenerations,population,maze) == false) {
			// Print fittest individual from population
			Individual fittest = population.getFittest(0);
			System.out.println(
					"G" + generation + " Best solution (" + fittest.getFitness() + "): " + fittest.toString());

			// Apply crossover
			//population = ga.crossoverPopulation(population);
			population = ga.crossoverPopulation2(population);

			// Apply mutation
			population = ga.mutatePopulation(population);

			// Evaluate population
			ga.evalPopulation(population, maze);

			// Increment the current generation
			generation++;
		}

		//System.out.println("Stopped after " + maxGenerations + " generations.");
		System.out.println("Stopped after " + generation + " generations.");
		Individual fittest = population.getFittest(0);
		System.out.println("Best solution (" + fittest.getFitness() + "): " + fittest.toString());
		
	}
}
